package com.aptemo.webetek.client.widgets.betslip;

import java.util.ArrayList;
import java.util.List;

import com.aptemo.webetek.client.WebetekUserServiceAsync;
import com.aptemo.webetek.client.commands.GotAsynchCallback;
import com.aptemo.webetek.client.commands.impl.GetBetDetailsAction;
import com.aptemo.webetek.client.commands.impl.PlaceBetAction;
import com.aptemo.webetek.client.enums.EEditMode;
import com.aptemo.webetek.client.enums.EnumBetStatus;
import com.aptemo.webetek.client.events.BetPlacedEvent;
import com.aptemo.webetek.client.events.DeletePickEvent;
import com.aptemo.webetek.client.events.DeletePickHandler;
import com.aptemo.webetek.client.exceptions.BackendException.EErrorCodes;
import com.aptemo.webetek.client.mvp.BaseDisplay;
import com.aptemo.webetek.client.mvp.BasePresenter;
import com.aptemo.webetek.shared.BetBean;
import com.aptemo.webetek.shared.PickBean;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;

public class BetSlipPresenter implements BasePresenter, DeletePickHandler
{

	public interface Display extends BaseDisplay
	{
		HasClickHandlers getSubmitButton();

		HasValue<String> getStakePerBet();

		HasValue<Double> getPossibleWinnings();

		HasAllKeyHandlers getStakePerBetKeyHandler();

		double getAmount();

		HasText getInfoField();

		void renderList(List<PickBean> data, BetSlipPresenter handler);

		HasValue<Double> getTotalOdds();

		void setDisplayMode(EEditMode ereadonly);

		HasValue<String> getTotalAmountFinal();

		HasValue<Double> getTotalOddsFinal();

		HasValue<Double> getEarningsField();

		void switchToFinalMode(boolean value);

		String translate(String key);

		HasValue<Double> getTotalAmountField();
	}

	private HandlerManager			meventbus;
	private WebetekUserServiceAsync	rpcService;
	private Display					display;

	private List<PickBean>			mlist	= new ArrayList<PickBean>();
	private EEditMode				mode;
	private String					stakeId;
	private String					teamId;

	public BetSlipPresenter(Display view, HandlerManager eventbus, WebetekUserServiceAsync rpc, String id, String teamId)
	{
		meventbus = eventbus;
		rpcService = rpc;
		this.display = view;
		this.stakeId = id;
		this.teamId = teamId;
	}

	private void bind()
	{

		display.getSubmitButton().addClickHandler(new ClickHandler()
		{

			@Override
			public void onClick(ClickEvent event)
			{
				placeBet();
			}
		});

		display.getStakePerBetKeyHandler().addKeyUpHandler(new KeyUpHandler()
		{

			@Override
			public void onKeyUp(KeyUpEvent event)
			{
				try
				{
					updatePossibleWinnings();
				}
				catch (NumberFormatException e)
				{
					display.getInfoField().setText(display.translate("wrongNumberFormat"));
				}
			}

		});

	}

	protected void setMode(EEditMode mode)
	{
		this.mode = mode;
		display.setDisplayMode(mode);
	}

	private double getOddsSum()
	{
		double sum = 0.0;

		for (PickBean pick : mlist)
		{
			sum += pick.getOdds();
		}
		return sum;
	}

	@Override
	public void go(HasWidgets container)
	{
		container.clear();
		container.add(display.getDisplay());

		retrieveData();

		bind();
	}

	private void retrieveData()
	{
		if ((stakeId == null) || (stakeId.isEmpty()))
		{
			return;
		}
		GetBetDetailsAction action = new GetBetDetailsAction(this.stakeId);
		rpcService.invoke(action, new GotAsynchCallback<BetBean>()
		{

			@Override
			public void onError(String message, EErrorCodes code)
			{
				display.getInfoField().setText(message);
			}

			@Override
			public void onSuccess(BetBean stake)
			{
				List<PickBean> picks = stake.getPicks();
				mlist = picks;

				// fill stake per bet field
				// display.getTotalOdds().setText(getOddsSum() + "");
				display.getStakePerBet().setValue(stake.getAmount() / stake.getPicks().size() + "");
				display.getInfoField().setText(stake.getDate() + "");

				if (stake.getStatus() == EnumBetStatus.OPENED)
				{
					updatePossibleWinnings();
					// override edit mode
					setMode(EEditMode.EREADONLY);
				}
				else
				{
					updateWinnings(stake);
				}

			}
		});
	}

	@Override
	public void onPickDeleted(DeletePickEvent event)
	{
		// ignore delete handler if readonly
		if (this.mode == EEditMode.EREADONLY)
		{
			return;
		}
		String evid = event.getId();

		for (PickBean pick : mlist)
		{
			if (evid.equals(pick.getId()))
			{
				mlist.remove(pick);

				display.getInfoField().setText("");
				updatePossibleWinnings();
				break;
			}
		}
	}

	private void updateWinnings(BetBean stake)
	{
		// disable submit...
		setMode(EEditMode.EREADONLY);

		display.getTotalAmountFinal().setValue(stake.getAmount() + "");
		display.getTotalOddsFinal().setValue(stake.getOddsSum());
		display.getEarningsField().setValue(stake.getEarnings());

		display.switchToFinalMode(true);
		display.renderList(mlist, this);
	}

	private void updatePossibleWinnings() throws NumberFormatException
	{
		setMode(EEditMode.EEDIT);

		double win = 0.0;
		String strvalue = display.getStakePerBet().getValue();
		// if ((strvalue == null) || (strvalue.isEmpty()))
		// {
		// display.getStakePerBet().setValue();
		// }
		if ((strvalue != null) && (!strvalue.isEmpty()))
		{
			double val = Double.parseDouble(strvalue);
			// 
			if (val < 0)
			{
				// throw new NumberFormatException();
				display.getInfoField().setText(display.translate("stakeMustBeGreaterThan0"));
				val = 0.0;
			}
			win = val * getOddsSum();
			// update total field...
			display.getTotalAmountField().setValue(val * mlist.size());
		}

		display.getTotalOdds().setValue(getOddsSum());
		display.getPossibleWinnings().setValue(win);
		

		display.switchToFinalMode(false);
		display.renderList(mlist, this);
	}

	/**
	 * Send a command to backend.
	 * 
	 * 
	 */
	private void placeBet()
	{
		display.getInfoField().setText(display.translate("saving"));

		// check mode
		if (mode != EEditMode.EEDIT)
		{
			// display.getInfoField().setText("Wrong widget mode!");
			return;
		}

		double value = 0.0;
		try
		{
			value = display.getAmount();
			if (value <= 0.0)
			{
				throw new NumberFormatException();
			}
		}
		catch (NumberFormatException e)
		{
			display.getInfoField().setText(display.translate("stakeMustBeGreaterThan0"));
			display.getStakePerBet().setValue("1.0");
			updatePossibleWinnings();
			return;
		}

		// collect picks...
		ArrayList<String> picks = new ArrayList<String>();
		for (PickBean pick : mlist)
		{
			picks.add(pick.getId());
		}
		// create command action
		PlaceBetAction action = new PlaceBetAction(teamId, display.getAmount(), picks);

		rpcService.invoke(action, new GotAsynchCallback<BetBean>()
		{

			@Override
			public void onError(String message, EErrorCodes code)
			{
				display.getInfoField().setText(message);
			}

			@Override
			public void onSuccess(BetBean result)
			{
				display.translate("betPlaceSuccess");
				// clear widget...
				mlist.clear();
				// fire event
				meventbus.fireEvent(new BetPlacedEvent(teamId));
				updatePossibleWinnings();
			}

		});

	}

	/**
	 * Called when user picks a bet
	 * 
	 * The item is added to a pick list. Switch the mode.
	 * 
	 * @param pick
	 */
	public void addSelectedPick(PickBean pick)
	{
		// check mode to clear list
		if (mode == EEditMode.EREADONLY)
		{
			mlist.clear();
		}
		
		// clear input field
		if (mode == EEditMode.EREADONLY || mlist.size() == 0)
		{
			display.getInfoField().setText(display.translate("Betting"));
			// TODO ...assign value from minStake
			display.getStakePerBet().setValue("1");
		}

		if (mlist.size() >= 5)
		{
			display.getInfoField().setText(display.translate("picksNoExceeded"));
			return;
		}

		// take only one
		mlist.add(pick);
		//display.getInfoField().setText("");

		updatePossibleWinnings();
	}

	/**
	 * Called when user selects a stake
	 * 
	 * @param id
	 */
	public void addSelectedStake(String id)
	{
		this.stakeId = id;
		retrieveData();
	}

}
